home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 1: Comms & Networking / Almathera Ten on Ten - Disc 1: Comms & Networking.iso / tools / archie / archie-1.4 / vms_support.c < prev    next >
C/C++ Source or Header  |  1995-05-01  |  33KB  |  1,449 lines

  1. /* Emulation of 4.2 UNIX socket interface routines includes drivers for
  2.    Wollongong, CMU-TEK, UCX tcp/ip interface and also emulates the SUN
  3.    version of X.25 sockets.  The TWG will also work for MultiNet.  */
  4.  
  5. /* This is from unixlib, by P.Kay@massey.ac.nz; wonderful implementation.
  6.    You can get the real thing on 130.123.1.4 as unixlib_tar.z.  */
  7.  
  8. #include <stdio.h>
  9. #include <errno.h>
  10. #include <ssdef.h>
  11. #include <dvidef.h>
  12. #include <signal.h>
  13. #include <sys$library:msgdef.h>
  14. #include <iodef.h>
  15. #include <ctype.h>
  16. #include <vms.h>
  17. #include "[.vms]network.h"
  18.  
  19. #define QIO_FAILED (st != SS$_NORMAL || p[s].iosb[0] != SS$_NORMAL)
  20. #define QIO_ST_FAILED (st != SS$_NORMAL)
  21.  
  22. /* Socket routine.  */
  23. int
  24. VMSsocket (domain, type, protocol)
  25.      int domain, type, protocol;
  26. {
  27.   struct descriptor inetdesc, x25desc, mbxdesc;
  28.   int i, st, s, p_initialise ();
  29.   long ucx_sock_def;
  30.   char *getenv ();
  31.  
  32.   if (!tcp_make)
  33.     set_tcp_make ();
  34.  
  35.   if (p_initialised == 0)
  36.     {
  37.       for (i = 0; i < 32; i++)
  38.     p_initialise (i);
  39.  
  40.       p_initialised = 1;
  41.     }
  42.  
  43.   /* First of all, get a file descriptor and file ptr we can associate with
  44.      the socket, allocate a buffer, and remember the socket details.  */
  45.   s = dup (0);
  46.   if (s > 31)
  47.     {
  48.       errno = EMFILE;
  49.       close (s);
  50.       return -1;
  51.     }
  52.  
  53.   p[s].fptr = fdopen (s, "r");
  54.   p[s].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  55.   p[s].domain = domain;
  56.   p[s].type = type;
  57.   p[s].protocol = protocol;
  58.  
  59.   /* Handle the case of INET and X.25 separately.  */
  60.   if (domain == AF_INET)
  61.     {
  62.       if (tcp_make == NONE)
  63.     {
  64.       printf ("Trying to obtain a TCP socket when we don't have TCP!\n");
  65.       exit (1);
  66.     }
  67.       if (tcp_make == CMU)
  68.     {
  69.       /* For CMU we need only assign a channel.  */
  70.       inetdesc.size = 3;
  71.       inetdesc.ptr = "IP:";
  72.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  73.         return -1;
  74.     }
  75.       else if (tcp_make == UCX)
  76.     {
  77.       /* For UCX assign channel and associate a socket with it.  */
  78.       inetdesc.size = 3;
  79.       inetdesc.ptr = "BG:";
  80.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  81.         return -1;
  82.  
  83.       ucx_sock_def = (domain << 24) + (type << 16) + protocol;
  84.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  85.              &ucx_sock_def, 0, 0, 0, 0, 0);
  86.       if (QIO_FAILED)
  87.         return -1;
  88.     }
  89.       else
  90.     {
  91.       /* For TWG we assign the channel and associate a socket with it.  */
  92.       inetdesc.size = 7;
  93.       inetdesc.ptr = "_INET0:";
  94.  
  95.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  96.         return -1;
  97.  
  98.       st = sys$qiow (0, p[s].channel, IO$_SOCKET, p[s].iosb, 0, 0,
  99.              domain, type, 0, 0, 0, 0);
  100.       if (QIO_FAILED)
  101.         return -1;
  102.     }
  103.     }
  104.   else
  105.     /* We don't handle any other domains yet.  */
  106.     return -1;
  107.  
  108.   /* For each case if we are successful we return the descriptor.  */
  109.   return s;
  110. }
  111.  
  112. /* Bind routine.  */
  113. VMSbind (s, name, namelen)
  114.      int s;
  115.      union socket_addr *name;
  116.      int namelen;
  117. {
  118.   char infobuff[1024], lhost[32];
  119.   int st;
  120.  
  121.   if (!tcp_make)
  122.     set_tcp_make ();
  123.  
  124.   if (p[s].domain == AF_INET)
  125.     {
  126.       /* One main problem with bind is that if we're given a port number
  127.      of 0, then we're expected to return a unique port number.  Since
  128.      we don't KNOW, we return 1050+s and look to Lady Luck.  */
  129.       if (tcp_make == CMU)
  130.     {
  131.       if (name->in.sin_port == 0 && p[s].type != SOCK_DGRAM)
  132.         name->in.sin_port = 1050 + s;
  133.       p[s].namelen = namelen;
  134.       bcopy (name, &(p[s].name), namelen);
  135.  
  136.       if (p[s].type == SOCK_DGRAM)
  137.         {
  138.           /* Another problem is that CMU still needs an OPEN request
  139.          even if it's a datagram socket.  */
  140.           st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb,
  141.                  0, 0, 0, 0, ntohs (p[s].name.in.sin_port),
  142.                  0, 1, 0);
  143.           if (QIO_ST_FAILED)
  144.         return -1;
  145.  
  146.           p[s].cmu_open = 1;
  147.           sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
  148.             0, 0, &infobuff, 1024, 0, 0, 0, 0);
  149.           bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
  150.           p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
  151.  
  152.           /* So get it another way.  */
  153.           bcopy (infobuff + 136, lhost, infobuff[1]);
  154.           lhost[infobuff[1]] = '\0';
  155.           sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
  156.             0, 0, &infobuff, 1024, 1, lhost, 0, 0);
  157.           bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
  158.  
  159.           /* Be prepared to receive a message.  */
  160.           hang_a_read (s);
  161.         }
  162.     }
  163.       else if (tcp_make == UCX)
  164.     {
  165.       /* UCX will select a prot for you.  If the port's number is 0,
  166.          translate "name" into an item_2 list.  */
  167.       struct itemlist lhost;
  168.       lhost.length = namelen;
  169.       lhost.code = 0;
  170.       lhost.dataptr = (char *) name;
  171.  
  172.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  173.              0, 0, &lhost, 0, 0, 0);
  174.       if (QIO_FAILED)
  175.         return -1;
  176.  
  177.       if (p[s].type == SOCK_DGRAM)
  178.         hang_a_read (s);
  179.  
  180.     }
  181.       else
  182.     {
  183.       /* WG is more straightforward */
  184.       st = sys$qiow (0, p[s].channel, IO$_BIND, p[s].iosb,
  185.              0, 0, name, namelen, 0, 0, 0, 0);
  186.       if (QIO_FAILED)
  187.         return -1;
  188.  
  189.       /* If it's a datagram, get ready for the message.  */
  190.       if (p[s].type == SOCK_DGRAM)
  191.         hang_a_read (s);
  192.     }
  193.     }
  194.   else
  195.     /* We don't handle any other domain yet.  */
  196.     return -1;
  197.  
  198.   return 0;
  199. }
  200.  
  201. /* Connect routine.  */
  202. VMSconnect (s, name, namelen)
  203.      int s;
  204.      union socket_addr *name;
  205.      int namelen;
  206. {
  207.   int pr, fl, st;
  208.   char *inet_ntoa ();
  209.   static struct
  210.   {
  211.     int len;
  212.     char name[128];
  213.   } gethostbuf;
  214.   extern int connect_ast ();
  215.  
  216.   if (!tcp_make)
  217.     set_tcp_make ();
  218.  
  219.   /* For datagrams we need to remember who the name was so we can send all
  220.      messages to that address without having to specify it all the time.  */
  221.   if (p[s].connected)
  222.     {
  223.       if (p[s].connected == 1)
  224.     errno = EISCONN;
  225.       else
  226.     {
  227.       errno = ECONNREFUSED;
  228.       p[s].connected = 0;
  229.     }
  230.       return -1;
  231.     }
  232.  
  233.   if (p[s].connect_pending)
  234.     {
  235.       errno = EALREADY;
  236.       return -1;
  237.     }
  238.  
  239.   p[s].passive = 0;
  240.   p[s].tolen = namelen;
  241.   bcopy (name, &(p[s].to), namelen);
  242.  
  243.   if (p[s].domain == AF_INET)
  244.     {
  245.       if (tcp_make == CMU)
  246.     {
  247.  
  248.       /* Get the info about the remote host  and open up a connection.  */
  249.       st = sys$qiow (0, p[s].channel, GTHST, p[s].iosb, 0, 0, &gethostbuf,
  250.              132, 2, name->in.sin_addr.s_addr, 0, 0);
  251.       if (QIO_FAILED)
  252.         {
  253.           strcpy (gethostbuf.name, inet_ntoa (name->in.sin_addr.s_addr));
  254.           gethostbuf.len = strlen (gethostbuf.name);
  255.         }
  256.       gethostbuf.name[gethostbuf.len] = 0;
  257.  
  258.       /* TCP */
  259.       pr = 0;
  260.       /* Active */
  261.       fl = 1;
  262.  
  263.       /* Nothing else for datagrams.  */
  264.       if (p[s].type == SOCK_DGRAM)
  265.         return (0);
  266.       st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, connect_ast,
  267.             &p[s], &(gethostbuf.name), ntohs (name->in.sin_port),
  268.             ntohs (p[s].name.in.sin_port), fl, pr, 0);
  269.       if (QIO_ST_FAILED)
  270.         return -1;
  271.     }
  272.       else if (tcp_make == UCX)
  273.     {
  274.       /* Both UDP and TCP can use a connect - IO$_ACCESS */
  275.       p[s].rhost.length = namelen;
  276.       p[s].rhost.code = 0;
  277.       p[s].rhost.dataptr = (char *) name;
  278.  
  279.       st = sys$qio (s, p[s].channel, IO$_ACCESS, p[s].iosb, connect_ast,
  280.             &p[s], 0, 0, &p[s].rhost, 0, 0, 0);
  281.       if (QIO_ST_FAILED)
  282.         return -1;
  283.     }
  284.       else
  285.     {
  286.       /* TWG */
  287.       if (p[s].type == SOCK_DGRAM)
  288.         return (0);
  289.       st = sys$qio (s, p[s].channel, IO$_CONNECT, p[s].iosb, connect_ast,
  290.             &p[s], name, namelen, 0, 0, 0, 0);
  291.       if (QIO_ST_FAILED)
  292.         return -1;
  293.     }
  294.     }
  295.   else
  296.     /* We don't handle any other domain yet.  */
  297.     return -1;
  298.  
  299.   if (p[s].non_blocking)
  300.     {
  301.       if (p[s].connected)
  302.     {
  303.       if (p[s].connected == 1)
  304.         return 0;
  305.       else
  306.         {
  307.           p[s].connected = 0;
  308.           errno = ECONNREFUSED;
  309.           return -1;
  310.         }
  311.     }
  312.       else
  313.     {
  314.       p[s].connect_pending = 1;
  315.       errno = EINPROGRESS;
  316.       return -1;
  317.     }
  318.     }
  319.   else
  320.     {
  321.       /* wait for the connection to occur */
  322.       if (p[s].connected)
  323.     {
  324.       if (p[s].connected == 1)
  325.         return 0;
  326.       else
  327.         {
  328.           p[s].connected = 0;
  329.           errno = ECONNREFUSED;
  330.           return -1;
  331.         }
  332.     }
  333.  
  334.       /* Timed out? */
  335.       if (wait_efn (s) == -1)
  336.     return -1;
  337.  
  338.       if (p[s].connected != SS$_NORMAL)
  339.     {
  340.       errno = ECONNREFUSED;
  341.       return -1;
  342.     }
  343.  
  344.       return 0;
  345.     }
  346. }
  347.  
  348. /* Listen routine.  */
  349. VMSlisten (s, backlog)
  350.      int s;
  351.      int backlog;
  352. {
  353.   int st;
  354.  
  355.   if (!tcp_make)
  356.     set_tcp_make ();
  357.  
  358.   p[s].passive = 1;
  359.   p[s].backlog = backlog;
  360.   if (p[s].domain == AF_INET)
  361.     {
  362.       if (tcp_make == CMU)
  363.     {
  364.       /* For the CMU sockets we can't do the open call in listen;
  365.          we have to do it in hang_an_accept, because when we close
  366.          off the connection we have to be ready to accept another
  367.          one.  accept() also calls hang_an_accept on the old
  368.          descriptor.  */
  369.  
  370.       /* Nothing */
  371.     }
  372.       else if (tcp_make == UCX)
  373.     {
  374.  
  375.       /* Doc Verbage sez backlog is descriptor of byte.  Doc examples
  376.          and common sense say backlog is value.  Value doesn't work,
  377.          so let's try descriptor of byte after all.  */
  378.       struct descriptor bl;
  379.       unsigned char ucx_backlog;
  380.  
  381.       ucx_backlog = (unsigned char) backlog;
  382.       bl.size = sizeof (ucx_backlog);
  383.       bl.ptr = (char *) &ucx_backlog;
  384.  
  385.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  386.              0, 0, 0, &bl, 0, 0);
  387.       if (QIO_FAILED)
  388.         return -1;
  389.     }
  390.       else
  391.     {
  392.       /* TWG */
  393.       st = sys$qiow (0, p[s].channel, IO$_LISTEN, p[s].iosb, 0, 0,
  394.              backlog, 0, 0, 0, 0, 0);
  395.       if (QIO_FAILED)
  396.         return -1;
  397.     }
  398.     }
  399.   else
  400.     /* We don't handle any other domain yet.  */
  401.     return -1;
  402.  
  403.   p[s].status = LISTENING;
  404.   hang_an_accept (s);
  405.   return 0;
  406. }
  407.  
  408. /* Accept routine.  */
  409. int
  410. VMSaccept (s, addr, addrlen)
  411.      int s;
  412.      union socket_addr *addr;
  413.      int *addrlen;
  414. {
  415.   int news, st;
  416.   struct descriptor inetdesc;
  417.  
  418.   if (!tcp_make)
  419.     set_tcp_make ();
  420.  
  421.   if (p[s].non_blocking && !p[s].accept_pending)
  422.     {
  423.       errno = EWOULDBLOCK;
  424.       return -1;
  425.     }
  426.  
  427.   /* hang_an_accept set up an incoming connection request so we have first
  428.      to hang around until one appears or we time out.  */
  429.   if (p[s].domain == AF_INET)
  430.     {
  431.       if (tcp_make == CMU)
  432.     {
  433.       char infobuff[1024];
  434.  
  435.       /* Timed out?  */
  436.       if (wait_efn (s) == -1)
  437.         return -1;
  438.  
  439.       /* Ok, get a new descriptor ...  */
  440.       news = dup (0);
  441.       if (news > 31)
  442.         {
  443.           errno = EMFILE;
  444.           close (news);
  445.           return -1;
  446.         }
  447.  
  448.       /* ... and copy all of our data across.  */
  449.       bcopy (&p[s], &p[news], sizeof (p[0]));
  450.  
  451.       /* But not this field, of course! */
  452.       p[news].s = news;
  453.  
  454.       sys$qiow (0, p[news].channel, TCP$INFO, p[news].iosb,
  455.             0, 0, &infobuff, 1024, 0, 0, 0, 0);
  456.  
  457.       /* Copy across the connection info if necessary.  */
  458.       if (addr != 0)
  459.         {
  460.           *addrlen = sizeof (struct sockaddr_in);
  461.           bcopy (infobuff + 132, &(addr->in.sin_port), 2);
  462.           addr->in.sin_port = htons (addr->in.sin_port);
  463.           addr->in.sin_family = AF_INET;
  464.           bcopy (infobuff + 272, &(addr->in.sin_addr), 4);
  465.           p[news].fromlen = *addrlen;
  466.           bcopy (addr, &(p[news].from), *addrlen);
  467.         }
  468.       p[news].status = PASSIVE_CONNECTION;
  469.  
  470.       /* Get a new file ptr for the socket.  */
  471.       p[news].fptr = fdopen (news, "r");
  472.  
  473.       /* Reset this field.  */
  474.       p[news].accept_pending = 0;
  475.  
  476.       /* Allocate a buffer.  */
  477.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  478.       p[news].fd_leftover = 0;
  479.  
  480.       /* Be prepared to get msgs.  */
  481.       hang_a_read (news);
  482.  
  483.       /* Now fix up our previous socket so it's again listening
  484.          for connections.  */
  485.       inetdesc.size = 3;
  486.       inetdesc.ptr = "IP:";
  487.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  488.         return -1;
  489.       p[s].status = LISTENING;
  490.       hang_an_accept (s);
  491.  
  492.       /* Return the new socket descriptor.  */
  493.       return news;
  494.     }
  495.       else if (tcp_make == UCX)
  496.     {
  497.       /* UCX does the actual accept from hang_an_accept.  The accept info
  498.         is put into the data structure for the "listening" socket.
  499.         These just need to be copied into a newly allocated socket for
  500.         the connect and the listening socket re-started.  */
  501.  
  502.       /* Wait for event flag from accept being received inside
  503.          of hang_an_accept().  */
  504.  
  505.       if (wait_efn (s) == -1)
  506.         /* Timed out.  */
  507.         return -1;
  508.  
  509.       /* Ok, get a new descriptor ...  */
  510.       news = dup (0);
  511.       if (news > 31)
  512.         {
  513.           errno = EMFILE;
  514.           close (news);
  515.           return -1;
  516.         }
  517.       /* ... and copy all of our data across.  */
  518.       bcopy (&p[s], &p[news], sizeof (p[0]));
  519.       p[news].s = news;    /* but not this field */
  520.       p[news].channel = p[s].ucx_accept_chan;
  521.  
  522.       /* Initialize the remote host address item_list_3 struct.  */
  523.       p[news].rhost.length = sizeof (struct sockaddr_in);
  524.       p[news].rhost.code = 0;
  525.       p[news].rhost.dataptr = (char *) &p[news].from;
  526.       p[news].rhost.retlenptr = &p[news].fromdummy;
  527.  
  528.       if (addr != 0)
  529.         {
  530.           /* Return the caller's info, if requested.  */
  531.           *addrlen = p[news].fromdummy;
  532.           bcopy (&p[news].from, addr, p[news].fromdummy);
  533.         }
  534.  
  535.       /* Finish fleshing out the new structure.  */
  536.       p[news].status = PASSIVE_CONNECTION;
  537.  
  538.       /* Get a new file pointer for the socket.  */
  539.       p[news].fptr = fdopen (news, "r");
  540.  
  541.       /* Reset this field.  */
  542.       p[news].accept_pending = 0;
  543.  
  544.       /* Allocate a buffer.  */
  545.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  546.       p[news].fd_leftover = 0;
  547.  
  548.       /* Get it started reading.  */
  549.       hang_a_read (news);
  550.  
  551.       p[s].status = LISTENING;
  552.       hang_an_accept (s);
  553.  
  554.       return news;
  555.     }
  556.       else
  557.     {
  558.       /* TWG */
  559.       struct descriptor inetdesc;
  560.       int size;
  561.  
  562.       /* Time out?  */
  563.       if (wait_efn (s) == -1)
  564.         return -1;
  565.  
  566.       /* Ok, get a new descriptor ...  */
  567.       news = dup (0);
  568.       if (news > 31)
  569.         {
  570.           errno = EMFILE;
  571.           close (news);
  572.           return -1;
  573.         }
  574.  
  575.       /* Assign a new channel.  */
  576.       inetdesc.size = 7;
  577.       inetdesc.ptr = "_INET0:";
  578.       st = sys$assign (&inetdesc, &p[news].channel, 0, 0);
  579.       if (QIO_ST_FAILED)
  580.         {
  581.           p[s].accept_pending = 0;
  582.           sys$clref (s);
  583.           return -1;
  584.         }
  585.  
  586.       /* From info needs an int length field! */
  587.       size = sizeof (p[s].from) + 4;
  588.       st = sys$qiow (0, p[news].channel, IO$_ACCEPT, p[news].iosb, 0, 0,
  589.              &p[s].fromdummy, size, p[s].channel, 0, 0, 0);
  590.  
  591.       if (QIO_ST_FAILED || p[news].iosb[0] != SS$_NORMAL)
  592.         {
  593.           p[s].accept_pending = 0;
  594.           sys$clref (s);
  595.           return -1;
  596.         }
  597.  
  598.       if (addr != 0)
  599.         {
  600.           /* Return the caller's info if requested.  */
  601.           *addrlen = p[s].fromdummy;
  602.           bcopy (&p[s].from, addr, *addrlen);
  603.         }
  604.  
  605.       /* Fix up our new data structure.  */
  606.       p[news].status = PASSIVE_CONNECTION;
  607.       p[news].domain = AF_INET;
  608.       p[news].passive = 1;
  609.       p[news].fptr = fdopen (news, "r");
  610.       /* Allocate a buffer.  */
  611.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  612.  
  613.       /* Be prepared to accept msgs.  */
  614.       hang_a_read (news);
  615.  
  616.       /* Get the old descriptor back onto accepting.  */
  617.       hang_an_accept (s);
  618.       return news;
  619.     }
  620.     }
  621.   else
  622.     /* We don't handle any other domain yet.  */
  623.     return -1;
  624. }
  625.  
  626. /* Recv routine.  */
  627. int
  628. VMSrecv (s, buf, len, flags)
  629.      int s;
  630.      char *buf;
  631.      int len, flags;
  632. {
  633.   return recvfrom (s, buf, len, flags, 0, 0);
  634. }
  635.  
  636. /* Revfrom routine.  */
  637. int
  638. VMSrecvfrom (s, buf, len, flags, from, fromlen)
  639.      int s;
  640.      char *buf;
  641.      int len, flags;
  642.      union socket_addr *from;
  643.      int *fromlen;
  644. {
  645.   int number;
  646.  
  647.   if (!tcp_make)
  648.     set_tcp_make ();
  649.  
  650.   if (p[s].domain != AF_INET && p[s].domain != AF_X25)
  651.     return -1;
  652.  
  653.   /* If we're not onto datagrams, then it's possible that a previous
  654.      call to recvfrom didn't read all the data, and left some behind.
  655.      So first of all, look in our data buffer for any leftovers that
  656.      will satisfy this read.  */
  657.  
  658.   /* We couldn't satisfy the request from previous calls so we must now
  659.      wait for a message to come through.  */
  660.   if (wait_efn (s) == -1)
  661.     /* Timed out.  */
  662.     return -1;
  663.  
  664.   if (p[s].closed_by_remote == 1)
  665.     {
  666.       /* This could have happened! */
  667.       errno = ECONNRESET;
  668.       return -1;
  669.     }
  670.  
  671.   if (from != NULL)
  672.     {
  673.       if (tcp_make == CMU)
  674.     {
  675.       if (p[s].type == SOCK_DGRAM)
  676.         {
  677.           /* Not documented but we get the from data from the beginning of
  678.          the data buffer.  */
  679.           *fromlen = sizeof (p[s].from.in);
  680.           from->in.sin_family = AF_INET;
  681.           bcopy (&p[s].fd_buff[8], &(from->in.sin_port), 2);
  682.           from->in.sin_port = htons (from->in.sin_port);
  683.           bcopy (&p[s].fd_buff[0], &(from->in.sin_addr), 4);
  684.  
  685.           /* Remove the address data from front of data buffer.  */
  686.           bcopy (p[s].fd_buff + 12, p[s].fd_buff, p[s].fd_buff_size);
  687.         }
  688.       else
  689.         {
  690.           *fromlen = p[s].fromlen;
  691.           bcopy (&p[s].from, from, p[s].fromlen);
  692.         }
  693.     }
  694.       else if (tcp_make == UCX)
  695.     {
  696.       *fromlen = p[s].fromdummy;
  697.       bcopy (&p[s].from, from, p[s].fromdummy);
  698.     }
  699.       else
  700.     {
  701.       *fromlen = p[s].fromlen;
  702.       bcopy (&p[s].from, from, p[s].fromlen);
  703.     }
  704.     }
  705.  
  706.   /* We may've received too much.  */
  707.   number = p[s].fd_buff_size;
  708.   if (number <= len)
  709.     {
  710.       /* If we haven't give back all the data available.  */
  711.       bcopy (p[s].fd_buff, buf, number);
  712.       p[s].fd_leftover = 0;
  713.       hang_a_read (s);
  714.       return (number);
  715.     }
  716.   else
  717.     {
  718.       /* If we have too much data then split it up.  */
  719.       p[s].fd_leftover = p[s].fd_buff;
  720.       bcopy (p[s].fd_leftover, buf, len);
  721.       /* And change the pointers.  */
  722.       p[s].fd_leftover += len;
  723.       p[s].fd_buff_size -= len;
  724.       return (len);
  725.     }
  726. }
  727.  
  728. /* Send routine.  */
  729. int
  730. VMSsend (s, msg, len, flags)
  731.      int s;
  732.      char *msg;
  733.      int len, flags;
  734. {
  735.   return sendto (s, msg, len, flags, 0, 0);
  736. }
  737.  
  738. /* Sendto routine.  */
  739. int
  740. VMSsendto (s, msg, len, flags, to, tolen)
  741.      int s;
  742.      unsigned char *msg;
  743.      int len, flags;
  744.      union socket_addr *to;
  745.      int tolen;
  746. {
  747.   int i, j, st, size;
  748.   unsigned char udpbuf[BUF_SIZE + 12];
  749.   char infobuff[1024], lhost[32];
  750.   unsigned short int temp;
  751.  
  752.   if (!tcp_make)
  753.     set_tcp_make ();
  754.  
  755.   /* First remember who we sent it to and set the value of size.  */
  756.   if (to != 0)
  757.     {
  758.       p[s].tolen = tolen;
  759.       bcopy (to, &(p[s].to), tolen);
  760.       size = tolen;
  761.     }
  762.   else
  763.     size = 0;
  764.  
  765.   if (p[s].domain == AF_INET)
  766.     {
  767.       /* We might never have started a read for udp (socket/sendto) so
  768.      put one here.  */
  769.       if (p[s].type == SOCK_DGRAM)
  770.     hang_a_read (s);
  771.  
  772.       if (tcp_make == CMU)
  773.     {
  774.       if (p[s].type == SOCK_DGRAM)
  775.         {
  776.           /* We might never have opened up a udp connection yet,
  777.          so check.  */
  778.           if (p[s].cmu_open != 1)
  779.         {
  780.           st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb, 0, 0,
  781.                  0, 0, 0, 0, 1, 0);
  782.           if (QIO_ST_FAILED)
  783.             return -1;
  784.  
  785.           p[s].cmu_open = 1;
  786.           sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
  787.                 0, 0, &infobuff, 1024, 0, 0, 0, 0);
  788.           bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
  789.           p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
  790.           bcopy (infobuff + 136, lhost, infobuff[1]);
  791.           lhost[infobuff[1]] = '\0';
  792.           sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
  793.                 0, 0, &infobuff, 1024, 1, lhost, 0, 0);
  794.           bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
  795.         }
  796.  
  797.           /* This isn't well documented.  To send to a UDP socket, we
  798.          need to put the address info at the beginning of the
  799.          buffer.  */
  800.           bcopy (msg, udpbuf + 12, len);
  801.           bcopy (&p[s].to.in.sin_addr, udpbuf + 4, 4);
  802.           temp = ntohs (p[s].to.in.sin_port);
  803.           bcopy (&temp, udpbuf + 10, 2);
  804.           bcopy (&p[s].name.in.sin_addr, udpbuf, 4);
  805.           temp = ntohs (p[s].name.in.sin_port);
  806.           bcopy (&temp, udpbuf + 8, 2);
  807.           temp = len + 12;
  808.           st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
  809.                  udpbuf, temp, 0, 0, 0, 0);
  810.           if (QIO_FAILED)
  811.         return -1;
  812.         }
  813.       else
  814.         {
  815.           /* TCP (! UDP)  */
  816.           st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
  817.                  msg, len, 0, 0, 0, 0);
  818.           if (QIO_FAILED)
  819.         return -1;
  820.         }
  821.       return len;
  822.     }
  823.       else if (tcp_make == UCX)
  824.     {
  825.       struct itemlist rhost;
  826.       rhost.length = sizeof (struct sockaddr_in);
  827.       rhost.code = 0;
  828.       rhost.dataptr = (char *) &p[s].to;
  829.  
  830.       st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb, 0, 0,
  831.              msg, len, &rhost, 0, 0, 0);
  832.       if (QIO_FAILED)
  833.         return -1;
  834.  
  835.       return len;
  836.     }
  837.       else
  838.     {
  839.       /* TWG */
  840.       st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb,
  841.              0, 0, msg, len, 0, &p[s].to, size, 0);
  842.       if (QIO_FAILED)
  843.         return -1;
  844.  
  845.       return len;
  846.     }
  847.     }
  848.   else
  849.     /* We don't handle any other domain yet.  */
  850.     return -1;
  851. }
  852.  
  853. /* Getsockname routine.  */
  854. int
  855. VMSgetsockname (s, name, namelen)
  856.      int s;
  857.      union socket_addr *name;
  858.      int *namelen;
  859. {
  860.   int st;
  861.  
  862.   if (!tcp_make)
  863.     set_tcp_make ();
  864.  
  865.   if (p[s].domain == AF_INET)
  866.     {
  867.       if (tcp_make == CMU)
  868.     {
  869.       /* For CMU we just return values held in our data structure.  */
  870.       *namelen = p[s].namelen;
  871.       bcopy (&(p[s].name), name, *namelen);
  872.       return (0);
  873.     }
  874.       else if (tcp_make == UCX)
  875.     {
  876.       /* An item_list_3 descriptor.  */
  877.       struct itemlist lhost;
  878.  
  879.       lhost.length = *namelen;
  880.       lhost.code = 0;
  881.       lhost.dataptr = (char *) name;
  882.  
  883.       /* Fill in namelen with actual ret len value.  */
  884.       lhost.retlenptr = (short int *) namelen;
  885.  
  886.       st = sys$qiow (0, p[s].channel, IO$_SENSEMODE, p[s].iosb, 0, 0,
  887.              0, 0, &lhost, 0, 0, 0);
  888.       if (QIO_FAILED)
  889.         return -1;
  890.  
  891.       return 0;
  892.     }
  893.       else
  894.     {
  895.       /* TWG gives us the information. */
  896.       st = sys$qiow (0, p[s].channel, IO$_GETSOCKNAME, p[s].iosb,
  897.              0, 0, name, namelen, 0, 0, 0, 0);
  898.       if (QIO_FAILED)
  899.         return -1;
  900.  
  901.       return 0;
  902.     }
  903.     }
  904.   else
  905.     /* We don't handle any other domain yet.  */
  906.     return -1;
  907. }
  908.  
  909. /* Select routine.  */
  910. int
  911. VMSselect (nfds, readfds, writefds, exceptfds, timeout)
  912.      int nfds;
  913.      fd_set *readfds, *writefds, *exceptfds;
  914.      struct timeval *timeout;
  915. {
  916.   int timer, fd, alarm_set, total, end;
  917.   long mask, cluster;
  918.   struct descriptor termdesc;
  919.   static fd_set new_readfds, new_writefds, new_exceptfds;
  920.  
  921.   FD_ZERO (&new_readfds);
  922.   FD_ZERO (&new_writefds);
  923.   FD_ZERO (&new_exceptfds);
  924.   total = 0;
  925.  
  926.   /* Assign a terminal channel if we haven't already.  */
  927.   if (terminal.chan == -1)
  928.     {
  929.       termdesc.size = 10;
  930.       termdesc.ptr = "SYS$INPUT:";
  931.       sys$assign (&termdesc, &terminal.chan, 0, 0);
  932.     }
  933.   alarm_set = 0;
  934.   if (timeout != NULL)
  935.     {
  936.       /* If a timeout is given then set the alarm.  */
  937.       end = timeout->tv_sec;
  938.       if (timer != 0)
  939.     {
  940.       /* We need to reset the alarm if it didn't fire, but we set it.  */
  941.       alarm_set = 1;
  942.       si_alarm (end);
  943.     }
  944.     }
  945.   else
  946.     end = 1;
  947.  
  948.   do
  949.     {
  950.       if (exceptfds)
  951.     {
  952.        /* Nothing */ ;
  953.     }
  954.  
  955.       if (writefds)
  956.     {
  957.       for (fd = 0; fd < nfds; fd++)
  958.         if (FD_ISSET (fd, writefds))
  959.           {
  960.         if (p[fd].connect_pending)
  961.            /* Nothing */ ;
  962.         else if ((p[fd].status == ACTIVE_CONNECTION)
  963.              || (p[fd].status == PASSIVE_CONNECTION))
  964.           {
  965.             FD_SET (fd, &new_writefds);
  966.             total++;
  967.           }
  968.           }
  969.     }
  970.  
  971.       if (readfds)
  972.     {
  973.       /* True if data pending or an accept.  */
  974.       for (fd = 3; fd < nfds; fd++)
  975.         if (FD_ISSET (fd, readfds) &&
  976.         ((p[fd].fd_buff_size != -1) || (p[fd].accept_pending == 1)))
  977.           {
  978.         FD_SET (fd, &new_readfds);
  979.         total++;
  980.           }
  981.     }
  982.  
  983.       if (total || (end == 0))
  984.     break;
  985.  
  986.       /* Otherwise, wait on an event flag.  It's possible that the wait can
  987.      be stopped by a spurious event flag being set -- i.e. one that's
  988.      got a status not normal.  So we've got to be prepared to loop
  989.      around the wait until a valid reason happens.  */
  990.  
  991.       /* Set up the wait mask.  */
  992.       cluster = 0;
  993.       mask = 0;
  994.       for (fd = 3; fd < nfds; fd++)
  995.     {
  996.       sys$clref (fd);
  997.       if (readfds)
  998.         if FD_ISSET
  999.           (fd, readfds) mask |= (1 << fd);
  1000.       if (writefds)
  1001.         if FD_ISSET
  1002.           (fd, writefds) mask |= (1 << fd);
  1003.       if (exceptfds)
  1004.         if FD_ISSET
  1005.           (fd, exceptfds) mask |= (1 << fd);
  1006.     }
  1007.  
  1008.       mask |= (1 << TIMER_EFN);
  1009.  
  1010.       /* Clear it off just in case.  */
  1011.       sys$clref (TIMER_EFN);
  1012.  
  1013.       /* Wait around.  */
  1014.       sys$wflor (cluster, mask);
  1015.  
  1016.       mask = 0;
  1017.       if (read_efn (TIMER_EFN))
  1018.     {
  1019.       errno = EINTR;
  1020.       break;
  1021.     }
  1022.   } while (1);
  1023.   /*NOTREACHED*/
  1024.  
  1025.   /* Unset the alarm if we set it.  */
  1026.   if (alarm_set == 1)
  1027.     alarm (0);
  1028.  
  1029.   if (readfds)
  1030.     *readfds = new_readfds;
  1031.  
  1032.   if (writefds)
  1033.     *writefds = new_writefds;
  1034.  
  1035.   if (exceptfds)
  1036.     *exceptfds = new_exceptfds;
  1037.  
  1038.   return total;
  1039. }
  1040.  
  1041. /* Shutdown routine.  */
  1042. VMSshutdown (s, how)
  1043.      int s, how;
  1044. {
  1045.   int st;
  1046.   int ucx_how;
  1047.  
  1048.   if (!tcp_make)
  1049.     set_tcp_make ();
  1050.  
  1051.   if (p[s].domain == AF_INET)
  1052.     {
  1053.       if (tcp_make == CMU)
  1054.     {
  1055.       /* For CMU we just close off.  */
  1056.       si_close (s);
  1057.       return 0;
  1058.     }
  1059.       else if (tcp_make == UCX)
  1060.     {
  1061.       st = sys$qiow (0, p[s].channel, IO$_DEACCESS | IO$M_SHUTDOWN,
  1062.              p[s].iosb, 0, 0, 0, 0, 0, how, 0, 0);
  1063.       if (QIO_FAILED)
  1064.         return -1;
  1065.  
  1066.       return 0;
  1067.     }
  1068.       else
  1069.     {
  1070.       /* TWG lets us do it.  */
  1071.       st = sys$qiow (0, p[s].channel, IO$_SHUTDOWN, p[s].iosb, 0, 0, how,
  1072.              0, 0, 0, 0, 0);
  1073.       if (QIO_FAILED)
  1074.         return -1;
  1075.  
  1076.       return 0;
  1077.     }
  1078.     }
  1079.   else                /* it wasn't a socket */
  1080.     return -1;
  1081. }
  1082.  
  1083. /*   */
  1084.  
  1085. /* The following routines are used by the above socket calls.  */
  1086.  
  1087. /* hang_a_read sets up a read to be finished at some later time.  */
  1088. hang_a_read (s)
  1089.      int s;
  1090. {
  1091.   extern int read_ast ();
  1092.   int size, st;
  1093.  
  1094.   /* Don't bother if we already did it.  */
  1095.   if (p[s].read_outstanding == 1)
  1096.     return;
  1097.  
  1098.   /* Have a read outstanding.  */
  1099.   p[s].read_outstanding = 1;
  1100.   size = sizeof (p[s].from) + 4;
  1101.   sys$clref (s);
  1102.  
  1103.   /* Clear off the event flag just in case, and reset the buf size.  */
  1104.   p[s].fd_buff_size = -1;
  1105.   if (p[s].domain == AF_INET)
  1106.     {
  1107.       if (tcp_make == CMU)
  1108.     {
  1109.       st = sys$qio (s, p[s].channel, TCP$RECEIVE, p[s].iosb, read_ast,
  1110.             &p[s], p[s].fd_buff, BUF_SIZE, 0, 0, 0, 0);
  1111.       if (QIO_ST_FAILED)
  1112.         return -1;
  1113.     }
  1114.       else if (tcp_make == UCX)
  1115.     {
  1116.  
  1117.       p[s].rhost.length = sizeof (struct sockaddr_in);
  1118.       p[s].rhost.code = 0;
  1119.       p[s].rhost.dataptr = (char *) &p[s].from;
  1120.       p[s].rhost.retlenptr = &p[s].fromdummy;
  1121.  
  1122.       st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
  1123.             &p[s], p[s].fd_buff, BUF_SIZE, &p[s].rhost, 0, 0, 0);
  1124.       if (QIO_ST_FAILED)
  1125.         return -1;
  1126.     }
  1127.       else
  1128.     {
  1129.       /* TWG */
  1130.       st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
  1131.             &p[s], p[s].fd_buff, BUF_SIZE, 0, &p[s].fromlen,
  1132.             size, 0);
  1133.       if (QIO_ST_FAILED)
  1134.         return -1;
  1135.     }
  1136.     }
  1137.   else
  1138.     /* We don't handle any other domain yet.  */
  1139.     return -1;
  1140. }
  1141.  
  1142. /* hang_an_accept waits for a connection request to come in.  */
  1143. hang_an_accept (s)
  1144.      int s;
  1145. {
  1146.   extern int accept_ast ();
  1147.   int st;
  1148.  
  1149.   /* Clear the event flag just in case.  */
  1150.   sys$clref (s);
  1151.  
  1152.   /* Reset our flag & buf size.  */
  1153.   p[s].accept_pending = 0;
  1154.   p[s].fd_buff_size = -1;
  1155.   if (p[s].domain == AF_INET)
  1156.     {
  1157.       if (tcp_make == CMU)
  1158.     {
  1159.       st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, accept_ast,
  1160.             &p[s], 0, 0, ntohs (p[s].name.in.sin_port), 0, 0, 0);
  1161.       if (QIO_ST_FAILED)
  1162.         return -1;
  1163.     }
  1164.       else if (tcp_make == UCX)
  1165.     {
  1166.       struct descriptor inetdesc;
  1167.  
  1168.       /* Assign channel for actual connection off listener.  */
  1169.       inetdesc.size = 3;
  1170.       inetdesc.ptr = "BG:";
  1171.       if (sys$assign (&inetdesc, &p[s].ucx_accept_chan, 0,
  1172.               0) != SS$_NORMAL)
  1173.         return -1;
  1174.  
  1175.       /* UCX's accept returns remote host info and the channel for a new
  1176.          socket to perform reads/writes on, so a sys$assign isn't
  1177.          really necessary.  */
  1178.       p[s].rhost.length = sizeof (struct sockaddr_in);
  1179.       p[s].rhost.dataptr = (char *) &p[s].from;
  1180.       p[s].fromdummy = 0;
  1181.       p[s].rhost.retlenptr = &p[s].fromdummy;
  1182.  
  1183.       st = sys$qio (s, p[s].channel, IO$_ACCESS | IO$M_ACCEPT, p[s].iosb,
  1184.             accept_ast, &p[s], 0, 0, &p[s].rhost,
  1185.             &p[s].ucx_accept_chan, 0, 0);
  1186.       if (QIO_ST_FAILED)
  1187.         return -1;
  1188.     }
  1189.       else
  1190.     {
  1191.       st = sys$qio (s, p[s].channel, IO$_ACCEPT_WAIT, p[s].iosb,
  1192.             accept_ast, &p[s], 0, 0, 0, 0, 0, 0);
  1193.       if (QIO_ST_FAILED)
  1194.         return -1;
  1195.     }
  1196.     }
  1197.   else
  1198.     /* We don't handle any other domain yet.  */
  1199.     return -1;
  1200. }
  1201.  
  1202. /* wait_efn just sets up a wait on either an event or the timer.  */
  1203. wait_efn (s)
  1204.      int s;
  1205. {
  1206.   long mask, cluster;
  1207.  
  1208.   cluster = 0;
  1209.   sys$clref (TIMER_EFN);
  1210.   mask = (1 << s) | (1 << TIMER_EFN);
  1211.   sys$wflor (cluster, mask);
  1212.  
  1213.   if (read_efn (TIMER_EFN))
  1214.     {
  1215.       errno = EINTR;
  1216.       return -1;
  1217.     }
  1218.  
  1219.   return 0;
  1220. }
  1221.  
  1222. /* read_ast is called by the system whenever a read is done.  */
  1223. read_ast (p)
  1224.      struct fd_entry *p;
  1225. {
  1226.   int i, j;
  1227.   unsigned char *v, *w;
  1228.  
  1229.   /* Reset the outstanding flag.  */
  1230.   p->read_outstanding = 0;
  1231.   if (p->iosb[0] == SS$_NORMAL)
  1232.     {
  1233.       /* Check no errors.  */
  1234.       p->fd_buff_size = p->iosb[1];
  1235.       if (tcp_make == CMU)
  1236.     {
  1237.       /* fiddle for DGRMs */
  1238.       if (p->type == SOCK_DGRAM)
  1239.         p->fd_buff_size -= 12;
  1240.     }
  1241.       if (p->sig_req == 1)
  1242.     gsignal (SIGIO);
  1243.     }
  1244.   else if (p->iosb[0] == SS$_CLEARED)
  1245.     p->closed_by_remote = 1;
  1246.   else if (tcp_make == UCX)
  1247.     {
  1248.       if (p->iosb[0] == SS$_LINKDISCON)
  1249.     p->closed_by_remote = 1;
  1250.     }
  1251. }
  1252.  
  1253. /* accept_ast is called whenever an incoming call is detected.  */
  1254. accept_ast (p)
  1255.      struct fd_entry *p;
  1256. {
  1257.   if (p->iosb[0] == SS$_NORMAL)
  1258.     p->accept_pending = 1;
  1259.   else
  1260.     /* If it failed set up another listen.  */
  1261.     listen (p->s, p[p->s].backlog);
  1262. }
  1263.  
  1264. /* connect_ast is called whenever an async connect is made.  */
  1265. connect_ast (p)
  1266.      struct fd_entry *p;
  1267. {
  1268.   p->connect_pending = 0;
  1269.   if ((p->connected = p->iosb[0]) == SS$_NORMAL)
  1270.     {
  1271.       /* We made the connection.  */
  1272.       p->status = ACTIVE_CONNECTION;
  1273.  
  1274.       /* Be prepared to accept a msg.  */
  1275.       hang_a_read (p->s);
  1276.     }
  1277. }
  1278.  
  1279. /*   */
  1280. /* These routines handle stream I/O.  */
  1281.  
  1282. /* si_close -- must close off any connection in progress.  */
  1283. si_close (s)
  1284.      int s;
  1285. {
  1286.   if (!tcp_make)
  1287.     set_tcp_make ();
  1288.  
  1289.   if ((s < 0) || (s > 31))
  1290.     return -1;
  1291.  
  1292.   if (p[s].channel != 0)
  1293.     {
  1294.       /* Was it one of our descriptors? */
  1295.       if (p[s].domain == AF_INET)
  1296.     {
  1297.       if (tcp_make == CMU)
  1298.         sys$qiow (0, p[s].channel, TCP$CLOSE, p[s].iosb,
  1299.               0, 0, 0, 0, 0, 0, 0, 0);
  1300.       if (p[s].status != HANDED_OFF)
  1301.         sys$dassgn (p[s].channel);
  1302.       close (s);
  1303.       free (p[s].fd_buff);
  1304.       p_initialise (s);
  1305.     }
  1306.       return 0;
  1307.     }
  1308.   else
  1309.     {
  1310.       /* Re-initialise data structure just in case.  */
  1311.       p[s].fd_buff_size = -1;
  1312.       p[s].accept_pending = 0;
  1313.       p[s].status = INITIALISED;
  1314.       return close (s);
  1315.     }
  1316. }
  1317.  
  1318. /* si_alarm -- insert a call to our own alarm function.  */
  1319. si_alarm (i)
  1320.      int i;
  1321. {
  1322.   extern int pre_alarm ();
  1323.  
  1324.   /* Make the call to pre_alarm instead of what the user wants;
  1325.      pre_alarm will call his routine when it finishes.  */
  1326.   /* VAX needs this call each time! */
  1327.   signal (SIGALRM, pre_alarm);
  1328.   alarm (i);
  1329. }
  1330.  
  1331. /* pre_alarm -- gets called first on an alarm signal.  */
  1332. pre_alarm ()
  1333. {
  1334.   /* Come here first so we can set our timer event flag.  */
  1335.   sys$setef (TIMER_EFN);
  1336.   (*alarm_function) ();
  1337. }
  1338.  
  1339. /* p_initialise - initialise our data array.  */
  1340. p_initialise (s)
  1341.      int s;
  1342. {
  1343.   int j;
  1344.   for (j = 0; j < 4; j++)
  1345.     p[s].iosb[j] = 0;
  1346.   p[s].channel = 0;
  1347.   p[s].fd_buff_size = -1;
  1348.   p[s].accept_pending = 0;
  1349.   p[s].connect_pending = 0;
  1350.   p[s].connected = 0;
  1351.   p[s].fd_buff = NULL;
  1352.   p[s].fd_leftover = NULL;
  1353.   p[s].fptr = NULL;
  1354.   p[s].s = s;
  1355.   p[s].name.in.sin_port = 0;
  1356.   p[s].masklen = 4;
  1357.   for (j = 0; j < 16; j++)
  1358.     p[s].mask[j] = 0xff;
  1359.   p[s].need_header = 0;
  1360.   p[s].status = INITIALISED;
  1361.   p[s].read_outstanding = 0;
  1362.   p[s].cmu_open = 0;
  1363.   p[s].x25_listener = 0;
  1364.   p[s].mother = s;
  1365.   p[s].child = 0;
  1366.   p[s].no_more_accepts = 0;
  1367.   p[s].closed_by_remote = 0;
  1368.   p[s].non_blocking = 0;
  1369.   p[s].sig_req = 0;
  1370.   sys$clref (s);
  1371. }
  1372.  
  1373. /* read_efn -- see whether an event flag is set.  */
  1374. read_efn (i)
  1375.      int i;
  1376. {
  1377.   int j;
  1378.   sys$readef (i, &j);
  1379.   j &= (1 << i);
  1380.  
  1381.   return j;
  1382. }
  1383.  
  1384. static
  1385. set_tcp_make ()
  1386. {
  1387.   struct descriptor inetdesc;
  1388.   int channel;
  1389.   /* first try CMU */
  1390.   inetdesc.size = 3;
  1391.   inetdesc.ptr = "IP:";
  1392.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  1393.     {
  1394.       sys$dassgn (channel);
  1395.       tcp_make = CMU;
  1396.       return;
  1397.     }
  1398.  
  1399.   /* next try TWG */
  1400.   inetdesc.size = 7;
  1401.   inetdesc.ptr = "_INET0:";
  1402.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  1403.     {
  1404.       sys$dassgn (channel);
  1405.       tcp_make = WG;
  1406.       return;
  1407.     }
  1408.  
  1409.   /* next try UCX */
  1410.   inetdesc.size = 4;
  1411.   inetdesc.ptr = "BG0:";
  1412.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  1413.     {
  1414.       sys$dassgn (channel);
  1415.       tcp_make = UCX;
  1416.       return;
  1417.     }
  1418.  
  1419.   /* nothing there oh dear!*/
  1420.   tcp_make = NONE;
  1421.   return;
  1422. }
  1423.  
  1424. static char *
  1425. getdevicename (channel)
  1426.      unsigned short int channel;
  1427. {
  1428.   int st;
  1429.   struct
  1430.   {
  1431.     struct itemlist id;
  1432.     int eol;
  1433.   } itmlst;
  1434.   static char name[64];
  1435.   short int lgth;
  1436.  
  1437.   name[0] = '\0';
  1438.   itmlst.id.code = DVI$_DEVNAM;
  1439.   itmlst.id.length = 64;
  1440.   itmlst.id.dataptr = name;
  1441.   itmlst.id.retlenptr = &lgth;
  1442.   itmlst.eol = 0;
  1443.   st = sys$getdvi (0, channel, 0, &itmlst, 0, 0, 0, 0);
  1444.   if (QIO_ST_FAILED)
  1445.     fprintf (stderr, "error getting device name %d\n", st);
  1446.  
  1447.   return (name);
  1448. }
  1449.